/**
 * @file opencv_014.cpp
 * @author 逆流 (1171267147@qq.com)
 * @brief 使用xml或yaml保存矩阵数据
 * @version 0.1
 * @date 2024-07-10
 *
 * @copyright Copyright (c) 2024.
 *
 */

#include <opencv2/opencv.hpp>
#include <string>
#define DOCTEST_CONFIG_IMPLEMENT_WITH_MAIN
#include "doctest/doctest.h"

using namespace std;
using namespace cv;

class MyData {
public:
    MyData() : a_(0), x_(0), id_() {}
    explicit MyData(int val) : a_(val), x_(CV_PI), id_("mydata1234") {}

    void Write(FileStorage& fs) const { fs << "{" << "A" << a_ << "X" << x_ << "ID" << id_ << "}"; }

    void Read(const FileNode& node) {
        a_  = static_cast<int>(node["A"]);
        x_  = static_cast<double>(node["X"]);
        id_ = (string)node["ID"];
    }

    int    get_a() const { return a_; }
    double get_x() const { return x_; }
    string get_id() const { return id_; }

private:
    int    a_;
    double x_;
    string id_;
};

//! 必须定义如下write和read函数，才能让FileStorage序列化正常工作
static void write(FileStorage& fs, const string&, const MyData& x) { x.Write(fs); }

static void read(const FileNode& node, MyData& x, const MyData& default_value = MyData()) {
    if (node.empty())
        x = default_value;
    else
        x.Read(node);
}

static ostream& operator<<(ostream& out, const MyData& m) {
    stringstream ss;
    ss << "{ ";
    ss << "id = " << m.get_id() << ", ";
    ss << "a = " << m.get_a() << ", ";
    ss << "x = " << m.get_x();
    ss << "}";
    out << ss.str() << endl;
    return out;
}

TEST_CASE("save to xml") {
    const string filename = "test.xml";
    FileStorage  fs_write(filename, FileStorage::WRITE);

    Mat R = (Mat_<double>(3, 3) << 1, 2, 3, 4, 5, 6, 7, 8, 9);
    Mat T = (Mat_<double>(3, 1) << 1, 2, 3);

    fs_write << "R" << R << "T" << T;
    fs_write.release();

    FileStorage fs_read(filename, FileStorage::READ);
    Mat         R1, T1;
    fs_read["R"] >> R1;
    fs_read["T"] >> T1;
    fs_read.release();

    cout << "R1 = " << R1 << endl;
    cout << "T1 = " << T1 << endl;
}

TEST_CASE("save to yaml") {
    const string filename = "test.yml";
    FileStorage  fs_write(filename, FileStorage::WRITE);

    MyData m(12);

    fs_write << "data" << m;
    fs_write.release();

    MyData      m2;
    FileStorage fs_read(filename, FileStorage::READ);

    fs_read["data"] >> m2;
    fs_read.release();

    cout << "m2 = " << m2;
}
